package model

import (
	"github.com/go-gin-admin/global"
	"github.com/go-gin-admin/util"
	"github.com/jinzhu/gorm"
)

type IMenu interface {
	AddMenu() (int64, error)           // 添加菜单
	DeleteMenu(menuId int64) error     // 删除菜单
	UpdateMenu() error                 // 更新菜单
	GetMenuTree() (interface{}, error) // 获取菜单树
}

type Menu struct {
	MenuId     int64   `json:"menuId" gorm:"primary_key"`  // 菜单id
	MenuName   string  `json:"menuName"`                   // 菜单名称
	Title      string  `json:"title"`                      // 标题
	Icon       string  `json:"icon"`                       // 图标
	Path       string  `json:"path"`                       // 路由
	Paths      string  `json:"paths"`                      // 菜单路径id
	MenuType   string  `json:"menuType"`                   // 菜单类型
	Action     string  `json:"action"`                     // 请求类型
	Permission string  `json:"permission"`                 // 权限
	ParentId   int64   `json:"parentId"`                   // 父级id
	NoCache    string  `json:"noCache"`                    // 未知
	Breadcrumb string  `json:"breadcrumb"`                 // 面包屑
	Component  string  `json:"component"`                  // 组件路径
	Sort       int64   `json:"sort"`                       // 排序
	Visible    string  `json:"visible"`                    // 是否可见
	IsIframe   string  `json:"isIframe"`                   // 是否是是否是iframe引入
	DelFlag    string  `json:"delFlag" gorm:"default:'0'"` // 删除标识符
	Children   []*Menu `json:"children"`                   // 子级
	BaseModel
}

// 前端tree需要的格式
type MenuLabel struct {
	Id    int64  `json:"id"`
	Label string `json:"label"`
	//ParentId int64       `json:"parentId"`
	Children []MenuLabel `json:"children"`
}

// 添加菜单
func (m *Menu) AddMenu() (int64, error) {
	// 查询父id数据
	row, err := getMenuRow(m.ParentId, "0")
	if err != nil {
		return 0, err
	}
	// 开启事务
	tx := global.GDB.Begin()
	// 增加菜单
	if err = tx.Table("sys_menu").Create(&m).Error; err != nil {
		tx.Rollback()
		return 0, err
	}
	// 拼接路径信息
	paths := ""
	if row.MenuId == 0 {
		// 更新新插入的数据的dept_path
		paths += "/0" + "/" + util.IntToString(m.MenuId)
	} else {
		paths = row.Paths + "/" + util.IntToString(m.MenuId)
	}
	// 更新新增的paths
	if err = tx.Table("sys_menu").Where("menu_id = ?", m.MenuId).Update("paths", paths).Error; err != nil {
		tx.Rollback()
		return 0, err
	}
	tx.Commit()
	return m.MenuId, nil
}

// 删除菜单
func (m *Menu) DeleteMenu(menuId int64) error {
	// 获取当前删除的信息
	row, _ := getMenuRow(menuId, "0")
	table := global.GDB.Table("sys_menu")
	table = table.Where("paths LIKE ?", row.Paths+"%")
	if err := table.Update("del_flag", "1").Error; err != nil {
		return err
	}
	return nil
}

// 更新菜单
func (m *Menu) UpdateMenu() error {
	table := global.GDB.Table("sys_menu")
	table = table.Where("menu_id = ?", m.MenuId)
	if err := table.Updates(map[string]interface{}{"menu_name": m.MenuName, "title": m.Title, "icon": m.Icon, "path": m.Path, "menu_type": m.MenuType, "action": m.Action, "permission": m.Permission, "no_cache": m.NoCache, "breadcrumb": m.Breadcrumb, "component": m.Component, "sort": m.Sort, "visible": m.Visible, "is_iframe": m.IsIframe, "update_time": m.UpdateTime}).Error; err != nil {
		return err
	}
	return nil
}

// 获取菜单树
func (m *Menu) GetMenuTree() (interface{}, error) {
	menuList, err := getMenuList()
	if err != nil {
		return nil, err
	}
	tree, err := menuListConvertTree(menuList)
	if err != nil {
		return nil, err
	}
	return tree, nil
}


// 获取当前行
func getMenuRow(id int64, state string) (Menu, error) {
	var menu Menu
	table := global.GDB.Table("sys_menu")
	table = table.Where("menu_id =?", id)
	table = table.Where("del_flag =?", state)
	if err := table.Select("menu_id, menu_name, title, icon, path, paths, menu_type, action, parent_id, no_cache, breadcrumb, component, sort, visible, is_iframe, create_time, update_time, del_flag").First(&menu).Error; err != nil {
		// 判断错误
		switch {
		case err == gorm.ErrRecordNotFound:
			// 说明没有找到
			return menu, nil
		case err != nil:
			return menu, err
		}
	}
	return menu, nil
}

// 获取所有的菜单列表
func getMenuList() ([]Menu, error) {
	var menuList []Menu
	table := global.GDB.Table("sys_menu")
	table = table.Where("del_flag = ?", "0")
	if err := table.Select("menu_id, menu_name, title, icon, path, paths, menu_type, action, parent_id, no_cache, breadcrumb, component, sort, visible, is_iframe, create_time, update_time, del_flag").Find(&menuList).Error; err != nil {
		return menuList, err
	}
	return menuList, nil
}

// 菜单转为tree
func menuListConvertTree(menu []Menu) (interface{}, error) {
	menus := make([]*Menu, 0)
	for i := 0; i < len(menu); i++ {
		// 如果当前部门的parentId为0，说明是顶级，直接加入到depts
		if menu[i].ParentId == 0 {
			menus = append(menus, &menu[i])
		}
		for j := 0; j < len(menu); j++ {
			// 如果当前节点的parentId等于等于第一层节点的id，说明是下一层级的节点
			if menu[j].ParentId == menu[i].MenuId {
				menu[i].Children = append(menu[i].Children, &menu[j])
			}
		}
	}
	// 获取所有
	return menus, nil
}

func (m *MenuLabel) GetMenuElementUiTree() (mk []MenuLabel, err error) {
	menuList, err := getMenuList()
	if err != nil {
		return nil, err
	}

	// 递归
	mk = make([]MenuLabel, 0)
	for i := 0; i < len(menuList); i++ {
		if menuList[i].ParentId != 0 {
			continue
		}
		e := MenuLabel{}
		e.Id = menuList[i].MenuId
		e.Label = menuList[i].Title
		menusInfo := DiguiMenuLable(&menuList, e)

		mk = append(mk, menusInfo)
	}
	return

}

// 菜单转为tree
//func menuLabelListConvertTree(menuLabel []MenuLabel) (interface{}, error) {
//	menus := make([]*MenuLabel, 0)
//	for i := 0; i < len(menuLabel); i++ {
//		// 如果当前部门的parentId为0，说明是顶级，直接加入到depts
//		if menuLabel[i].ParentId == 0 {
//			menus = append(menus, &menuLabel[i])
//		}
//		for j := 0; j < len(menuLabel); j++ {
//			// 如果当前节点的parentId等于等于第一层节点的id，说明是下一层级的节点
//			if menuLabel[j].ParentId == menuLabel[i].Id {
//				menuLabel[i].Children = append(menuLabel[i].Children, menuLabel[j])
//			}
//		}
//	}
//	// 获取所有
//	return menus, nil
//}

// 递归查询
func DiguiMenuLable(menulist *[]Menu, menu MenuLabel) MenuLabel {
	list := *menulist

	min := make([]MenuLabel, 0)
	for j := 0; j < len(list); j++ {

		if menu.Id != list[j].ParentId {
			continue
		}
		mi := MenuLabel{}
		mi.Id = list[j].MenuId
		mi.Label = list[j].Title
		mi.Children = []MenuLabel{}
		if list[j].MenuType != "F" {
			ms := DiguiMenuLable(menulist, mi)
			min = append(min, ms)
		} else {
			min = append(min, mi)
		}

	}
	menu.Children = min
	return menu
}

// 获取角色的菜单列表
func GetMenuTreeByRole(roleKeys []string) (interface{}, error) {
	var menuList []Menu
	table := global.GDB.Table("sys_role_menu srm")
	table = table.Select("sm.menu_id, sm.menu_name, sm.title, sm.icon, sm.path, sm.paths, sm.menu_type, sm.action, sm.permission, sm.parent_id, sm.no_cache, sm.breadcrumb, sm.component, sm.sort, sm.visible, sm.is_iframe, sm.create_time, sm.update_time, sm.del_flag")
	table = table.Joins("LEFT JOIN sys_menu sm ON srm.menu_id = sm.menu_id")
	table = table.Where("sm.del_flag = ?", "0")
	if err := table.Where("srm.role_key IN (?)", roleKeys).Find(&menuList).Error; err != nil {
		return menuList, err
	}

	tree, err := menuListConvertTree(menuList)
	if err != nil {
		return nil, err
	}
	return tree, nil
}
